Clover icon

compiler

  1. Project Clover database Mon Jan 2 2023 15:09:37 MST
  2. Package com.google.javascript.jscomp

File TypeInferencePass.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

0
23
9
3
157
83
10
0.43
2.56
3
1.11

Classes

Class Line # Actions
TypeInferencePass 32 21 6 1
0.9615384396.2%
TypeInferencePass.FirstScopeBuildingCallback 125 1 2 0
1.0100%
TypeInferencePass.SecondScopeBuildingCallback 137 1 2 0
1.0100%
 

Contributing tests

This file is covered by 6329 tests. .

Source view

1    /*
2    * Copyright 2009 The Closure Compiler Authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16   
17    package com.google.javascript.jscomp;
18   
19    import com.google.common.base.Preconditions;
20    import com.google.common.collect.Maps;
21    import com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec;
22    import com.google.javascript.jscomp.NodeTraversal.AbstractScopedCallback;
23    import com.google.javascript.jscomp.type.ReverseAbstractInterpreter;
24    import com.google.javascript.rhino.Node;
25   
26    import java.util.Map;
27   
28    /**
29    * A compiler pass to run the type inference analysis.
30    *
31    */
 
32    class TypeInferencePass implements CompilerPass {
33   
34    static final DiagnosticType DATAFLOW_ERROR = DiagnosticType.warning(
35    "JSC_INTERNAL_ERROR_DATAFLOW",
36    "non-monotonic data-flow analysis");
37   
38    private final AbstractCompiler compiler;
39    private final ReverseAbstractInterpreter reverseInterpreter;
40    private Scope topScope;
41    private MemoizedScopeCreator scopeCreator;
42    private final Map<String, AssertionFunctionSpec> assertionFunctionsMap;
43   
 
44  6919 toggle TypeInferencePass(AbstractCompiler compiler,
45    ReverseAbstractInterpreter reverseInterpreter,
46    Scope topScope, MemoizedScopeCreator scopeCreator) {
47  6919 this.compiler = compiler;
48  6919 this.reverseInterpreter = reverseInterpreter;
49  6919 this.topScope = topScope;
50  6919 this.scopeCreator = scopeCreator;
51   
52  6919 assertionFunctionsMap = Maps.newHashMap();
53  6919 for (AssertionFunctionSpec assertionFucntion :
54    compiler.getCodingConvention().getAssertionFunctions()) {
55  48391 assertionFunctionsMap.put(assertionFucntion.getFunctionName(),
56    assertionFucntion);
57    }
58    }
59   
60    /**
61    * Main entry point for type inference when running over the whole tree.
62    *
63    * @param externsRoot The root of the externs parse tree.
64    * @param jsRoot The root of the input parse tree to be checked.
65    */
 
66  6919 toggle @Override
67    public void process(Node externsRoot, Node jsRoot) {
68  6919 Node externsAndJs = jsRoot.getParent();
69  6919 Preconditions.checkState(externsAndJs != null);
70  6919 Preconditions.checkState(
71    externsRoot == null || externsAndJs.hasChild(externsRoot));
72   
73  6919 inferAllScopes(externsAndJs);
74    }
75   
76    /** Entry point for type inference when running over part of the tree. */
 
77  6919 toggle void inferAllScopes(Node node) {
78    // Type analysis happens in two major phases.
79    // 1) Finding all the symbols.
80    // 2) Propagating all the inferred types.
81    //
82    // The order of this analysis is non-obvious. In a complete inference
83    // system, we may need to backtrack arbitrarily far. But the compile-time
84    // costs would be unacceptable.
85    //
86    // We do one pass where we do typed scope creation for all scopes
87    // in pre-order.
88    //
89    // Then we do a second pass where we do all type inference
90    // (type propagation) in pre-order.
91    //
92    // We use a memoized scope creator so that we never create a scope
93    // more than once.
94    //
95    // This will allow us to handle cases like:
96    // var ns = {};
97    // (function() { /** JSDoc */ ns.method = function() {}; })();
98    // ns.method();
99    // In this code, we need to build the symbol table for the inner scope in
100    // order to propagate the type of ns.method in the outer scope.
101  6919 (new NodeTraversal(
102    compiler, new FirstScopeBuildingCallback(), scopeCreator))
103    .traverseWithScope(node, topScope);
104  6919 (new NodeTraversal(
105    compiler, new SecondScopeBuildingCallback(), scopeCreator))
106    .traverseWithScope(node, topScope);
107    }
108   
 
109  65171 toggle void inferScope(Node n, Scope scope) {
110  65171 TypeInference typeInference =
111    new TypeInference(
112    compiler, computeCfg(n), reverseInterpreter, scope,
113    assertionFunctionsMap);
114  65171 try {
115  65171 typeInference.analyze();
116   
117    // Resolve any new type names found during the inference.
118  65171 compiler.getTypeRegistry().resolveTypesInScope(scope);
119   
120    } catch (DataFlowAnalysis.MaxIterationsExceededException e) {
121  0 compiler.report(JSError.make(n.getSourceFileName(), n, DATAFLOW_ERROR));
122    }
123    }
124   
 
125    private class FirstScopeBuildingCallback extends AbstractScopedCallback {
 
126  65171 toggle @Override
127    public void enterScope(NodeTraversal t) {
128  65171 t.getScope();
129    }
130   
 
131  687434 toggle @Override
132    public void visit(NodeTraversal t, Node n, Node parent) {
133    // Do nothing
134    }
135    }
136   
 
137    private class SecondScopeBuildingCallback extends AbstractScopedCallback {
 
138  65171 toggle @Override
139    public void enterScope(NodeTraversal t) {
140    // Only infer the entry root, rather than the scope root.
141    // This ensures that incremental compilation only touches the root
142    // that's been swapped out.
143  65171 inferScope(t.getCurrentNode(), t.getScope());
144    }
145   
 
146  687434 toggle @Override
147    public void visit(NodeTraversal t, Node n, Node parent) {
148    // Do nothing
149    }
150    }
151   
 
152  65171 toggle private ControlFlowGraph<Node> computeCfg(Node n) {
153  65171 ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, false);
154  65171 cfa.process(null, n);
155  65171 return cfa.getCfg();
156    }
157    }